﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;
using System.Globalization;
using System.Web;
using System.Text.RegularExpressions;
using System.Web.UI;
using Kooboo.CMS.Sites.Models;

namespace KB
{
    public static class StringExtensions
    {
        private static readonly Regex StripStyleExpression = new Regex("<style([\\s\\S]*(?=</style>))", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);
        private static readonly Regex StripScriptExpression = new Regex("<script([\\s\\S]*(?=</script>))", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);
        private static readonly Regex StripHTMLExpression = new Regex("<\\S[^><]*>", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled);

        [DebuggerStepThrough]
        public static string FormatWith(this string source, params object[] args)
        {
            return string.Format(source, args);
        }

        [DebuggerStepThrough]
        public static string UrlEncode(this string source)
        {
            return HttpUtility.UrlEncode(source);
        }

        [DebuggerStepThrough]
        public static string UrlDecode(this string source)
        {
            return HttpUtility.UrlDecode(source);
        }

        [DebuggerStepThrough]
        public static string AttributeEncode(this string source)
        {
            return HttpUtility.HtmlAttributeEncode(source);
        }

        [DebuggerStepThrough]
        public static string HtmlEncode(this string source)
        {
            return HttpUtility.HtmlEncode(source);
        }

        [DebuggerStepThrough]
        public static string HtmlDecode(this string source)
        {
            return HttpUtility.HtmlDecode(source);
        }

        [DebuggerStepThrough]
        public static string[] SplitRemoveEmpty(this string source, string separator)
        {
            return SplitRemoveEmpty(source, new string[] { separator });
        }

        [DebuggerStepThrough]
        public static string[] SplitRemoveEmpty(this string source, string[] separator)
        {
            return source.Split(separator, StringSplitOptions.RemoveEmptyEntries);
        }

        [DebuggerStepThrough]
        public static T AsEnum<T>(this string source) where T : IComparable, IFormattable
        {
            return (T)Enum.Parse(typeof(T), source, true);
        }

        [DebuggerStepThrough]
        public static T AsEnum<T>(this string source, T defaultValue) where T : IComparable, IFormattable
        {
            if (!string.IsNullOrEmpty(source))
            {
                try
                {
                    return AsEnum<T>(source);
                }
                catch
                { }
            }

            return defaultValue;
        }

        [DebuggerStepThrough]
        public static string Cut(this string str, int leaveNum, string more = "...")
        {
            if (str.IsNullOrWhiteSpace())
            {
                return String.Empty;
            }
            if (str.Length <= leaveNum)
            {
                return str;
            }
            return str.Substring(0, leaveNum) + more ?? String.Empty;
        }

        [DebuggerStepThrough]
        public static bool EqualsIgnoreCase(this string str, string other)
        {
            return str.AsString().Equals(other, StringComparison.OrdinalIgnoreCase);
        }

        [DebuggerStepThrough]
        public static bool ContainsIgnoreCase(this string original, string value)
        {
            return original.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0;
        }

        [DebuggerStepThrough]
        public static bool StartWithIgnoreCase(this string str, string prefix)
        {
            return str.AsString().StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
        }

        [DebuggerStepThrough]
        public static bool EndWithIgnoreCase(this string str, string suffix)
        {
            return str.AsString().EndsWith(suffix, StringComparison.OrdinalIgnoreCase);
        }

        [DebuggerStepThrough]
        public static string Script(this string str)
        {
            return "<script type=\"text/javascript\">{0}</script>".FormatWith(str);
        }

        [DebuggerStepThrough]
        public static string AsNullIfEmpty(this string str)
        {
            return str.IsNullOrWhiteSpace() ? null : str;
        }

        [DebuggerStepThrough]
        public static bool IsNullOrEmpty(this string source)
        {
            return string.IsNullOrEmpty(source);
        }
        [DebuggerStepThrough]
        public static bool HasValue(this string source)
        {
            return !string.IsNullOrWhiteSpace(source);
        }
        [DebuggerStepThrough]
        public static bool IsNullOrWhiteSpace(this string source)
        {
            return string.IsNullOrWhiteSpace(source);
        }

        [DebuggerStepThrough]
        public static string PartItems(this string source, int itemIndex, string separator = ",")
        {

            if (source == null)
            {
                return string.Empty;
            }
            else
            {
                var items = source.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries);
                if (items.Length > itemIndex)
                {
                    return items[itemIndex];
                }
                else
                {
                    return string.Empty;
                }

            }
        }

        [DebuggerStepThrough]
        public static string StripHtmlXmlTags(this string content)
        {
            if (content.IsNullOrWhiteSpace())
            {
                return content;
            }
            return Regex.Replace(content, "<[^>]+>?", "", RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        [DebuggerStepThrough]
        public static string StripAllTags(this string stringToStrip)
        {
            if (string.IsNullOrEmpty(stringToStrip))
            {
                return stringToStrip;
            }
            // paring using RegEx
            //
            stringToStrip = Regex.Replace(stringToStrip, "</p(?:\\s*)>(?:\\s*)<p(?:\\s*)>", "\n\n", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            stringToStrip = Regex.Replace(stringToStrip, "<br(?:\\s*)/>", "\n", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            stringToStrip = Regex.Replace(stringToStrip, "\"", "''", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            stringToStrip = StripHtmlXmlTags(stringToStrip);

            return stringToStrip;
        }

        [DebuggerStepThrough]
        public static string Summary(this string src, int leaveNum, string more = "...")
        {
            var summary = src.StripHtmlXmlTags();
            return summary.Cut(leaveNum, more);
        }

        [DebuggerStepThrough]
        public static string FormatModel(this string format, object source)
        {
            if (format == null)
                throw new ArgumentNullException("format");

            var result = new StringBuilder(format.Length * 2);
            var expression = new StringBuilder();

            var e = format.GetEnumerator();
            while (e.MoveNext())
            {
                var ch = e.Current;
                if (ch == '{')
                {
                    while (true)
                    {
                        if (!e.MoveNext())
                            throw new FormatException();

                        ch = e.Current;
                        if (ch == '}')
                        {
                            result.Append(OutExpression(source, expression.ToString()));
                            expression.Length = 0;
                            break;
                        }
                        if (ch == '{')
                        {
                            result.Append(ch);
                            break;
                        }
                        expression.Append(ch);
                    }
                }
                else if (ch == '}')
                {
                    if (!e.MoveNext() || e.Current != '}')
                        throw new FormatException();
                    result.Append('}');
                }
                else
                {
                    result.Append(ch);
                }
            }

            return result.ToString();
        }
        private static string OutExpression(object source, string expression)
        {
            string format = "{0}";

            int colonIndex = expression.IndexOf(':');
            if (colonIndex > 0)
            {
                format = "{0:" + expression.Substring(colonIndex + 1) + "}";
                expression = expression.Substring(0, colonIndex);
            }

            try
            {
                return DataBinder.Eval(source, expression, format) ?? string.Empty;
            }
            catch (HttpException)
            {
                throw new FormatException();
            }
        }

        [DebuggerStepThrough]
        public static string ResolveUrl(this string url)
        {
            if (url.HasValue())
            {
                return url.TrimStart('~');
            }
            return "";
        }

        public static string ResizeImage(this string image, int width = 0, int height = 0)
        {
            if (image.IsNullOrEmpty())
            {
                return string.Empty;
            }
            return string.Format("/{0}/Kooboo-Resource/ResizeImage?url={1}&width={2}&height={3}", Site.Current.Name, image, width, height);
        }
    }
}